unit frmExeTrainerGeneratorUnit;

{$mode delphi}

interface

uses
  {$ifdef darwin}
  macport, math, LCLIntf,
  {$endif}
  {$ifdef windows}
  windows,
  {$endif}
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics,
  ExtCtrls, dialogs, StdCtrls, ComCtrls, Menus, CEFuncProc, IconStuff, zstream,
  registry, MainUnit2, symbolhandler, lua, lualib, lauxlib, betterControls;


type
  TFileData=class
    filepath: string;
    filename: string;
    folder: string;
  end;



  { TfrmExeTrainerGenerator }

  TfrmExeTrainerGenerator = class(TForm)
    Button1: TButton;
    btnGenerateTrainer: TButton;
    btnAddFile: TButton;
    btnRemoveFile: TButton;
    Button3: TButton;
    cbKernelDebug: TCheckBox;
    cbSpeedhack: TCheckBox;
    cbVEHDebug: TCheckBox;
    cbModPlayer: TCheckBox;
    cbD3DHook: TCheckBox;
    cbDotNet: TCheckBox;
    cbCCode: TCheckBox;
    cbIncludes: TCheckBox;
    comboCompression: TComboBox;
    GroupBox1: TGroupBox;
    GroupBox2: TGroupBox;
    GroupBox3: TGroupBox;
    GroupBox4: TGroupBox;
    Image1: TImage;
    Label1: TLabel;
    ListView1: TListView;
    miEditFolder: TMenuItem;
    OpenDialog1: TOpenDialog;
    Panel1: TPanel;
    Panel2: TPanel;
    Panel3: TPanel;
    Panel4: TPanel;
    pmFiles: TPopupMenu;
    cbTiny: TRadioButton;
    cbGigantic: TRadioButton;
    rb32: TRadioButton;
    rb64: TRadioButton;
    SelectDirectoryDialog1: TSelectDirectoryDialog;
    procedure btnAddFileClick(Sender: TObject);
    procedure btnRemoveFileClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure btnGenerateTrainerClick(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure cbCCodeChange(Sender: TObject);
    procedure cbTrainersizeChange(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ListView1ContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
    procedure ListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
    procedure miEditFolderClick(Sender: TObject);
    procedure pmFilesPopup(Sender: TObject);
  private
    { private declarations }
    saving: boolean;
    archive: Tcompressionstream;
    _archive: TMemoryStream;

    updatehandle: thandle;
    filecount: integer;

    addedFiles: tstringlist;

    procedure addFile(filename: string; folder: string='');
    procedure addFolder(basepath: string; folder: string='');
  public
    { public declarations }
    filename: string;
    procedure addFiletoList(fn: string);
    procedure addDirToList(dir: string);
  end; 

var
  frmExeTrainerGenerator: TfrmExeTrainerGenerator;

  exeTrainerFeatures: array of record
    featurename: string;
    functionid: integer;
    cb: TCheckBox;
  end;

implementation

{ TfrmExeTrainerGenerator }

uses MainUnit,ceguicomponents, OpenSave, Globals, LuaHandler, commonTypeDefs,
  libcepack;

resourcestring
  rsSaving = 'Saving...';
  rsGenerate = 'Generate';
  rsupdateFailed='Failure updating the trainer resource information: %d';
  rsFailureOnWriting = 'failure on writing';
  rsIconUpdateError = 'icon update error';
  rsFailureOpeningTheTrainerForResourceUpdates = 'Failure opening the trainer '
    +'for resource updates. Make sure you do not watch the creation';
  rsTheTrainerHasBeenSuccessfullyGenerated = 'The trainer has been '
    +'successfully generated';
  rsNone = 'None';
  rsFastest = 'Fastest';
  rsDefault = 'Default';
  rsMax = 'Max';
  rsNewFoldername = 'New foldername';
  rsCETrainerMaker = 'CE trainer maker';
  rsARCHIVE = ' ARCHIVE:';
  rsDECOMPRESSOR = ' DECOMPRESSOR:';
  rsInvalidIcon = '(Invalid icon)';
  rsInvalidIconType = '(Invalid icon type)';
  rsTrainerFileMissing = 'Copying %s.dat to %s failed. Please make sure the '
    +'file still exists';
  
procedure TfrmExeTrainerGenerator.FormActivate(Sender: TObject);
begin

end;

var roti: integer;
function rot: string;
begin
  result:='';
  roti:=(roti+1) mod 8;
  case roti of
    0: result:='-';
    1: result:='\';
    2: result:='|';
    3: result:='/';
    4: result:='-';
    5: result:='\';
    6: result:='|';
    7: result:='/';
  end;

end;

procedure TfrmExeTrainerGenerator.addFolder(basepath: string; folder: string='');
var
  dirinfo: TSearchRec;
  r: integer;
begin
  if (folder<>'') and ((folder[1]='\') or (folder[1]='/')) then
    folder:='';

  if basepath.EndsWith(PathDelim)=false then
    basepath:=basepath+PathDelim;

  zeromemory(@dirinfo, sizeof(TSearchRec));
  r := FindFirst(basepath+'*.*', FaAnyfile, DirInfo);
  while (r = 0) do
  begin
    if (DirInfo.Attr and FaVolumeId <> FaVolumeID) then
    begin
      if ((DirInfo.Attr and FaDirectory) <> FaDirectory) then
        addFile(basepath+DirInfo.Name, folder)
      else
      begin
        if (DirInfo.Name[1]<>'.') then
          addFolder(basepath + DirInfo.Name, folder+PathDelim+dirinfo.name);
      end;
    end;

    r := FindNext(DirInfo);
  end;
end;

procedure TfrmExeTrainerGenerator.addFile(filename: string; folder: string='');
var
  f: tmemorystream;
  currentfile: string;

  size: dword;
  i: qword;
  block: qword;
begin
  folder:=trim(folder);
  if (folder<>'') and ((folder[1]='\') or (folder[1]='/')) then
    folder:='';

  if addedfiles.IndexOf(folder+filename)<>-1 then exit; //it was already added earlier by the user

  f:=TMemoryStream.create;
  try
    f.LoadFromFile(filename);
    f.position:=0;
    size:=f.size;

    //write the filename
    currentfile:=extractfilename(filename);
    size:=length(currentfile);
    archive.write(size, sizeof(size));
    archive.write(currentfile[1], size);

    //write the relative folder
    size:=length(folder);
    archive.write(size, sizeof(size));
    archive.write(folder[1], size);

    //write the size, and the file itself
    size:=f.size;
    archive.Write(size, sizeof(size));

    i:=f.size;
    while i>0 do
    begin
      block:=min(qword(256*1024), i);
      archive.CopyFrom(f, block);
      dec(i,block);

      btnGenerateTrainer.caption:=rsSaving+rot;
      application.ProcessMessages;
    end;
    inc(filecount);

    addedfiles.add(folder+filename);
  finally
    f.free;
    btnGenerateTrainer.caption:=rsGenerate;
  end;
end;


procedure TfrmExeTrainerGenerator.btnGenerateTrainerClick(Sender: TObject);
var DECOMPRESSOR: TMemorystream;
  CETRAINER: string;
  icon: tmemorystream;

  z: ticon;

  ii: PICONDIR;
  gii: PGRPICONDIR absolute ii;

  compression: Tcompressionlevel;
  i,j,t,t2,ltop: integer;

  tiny: boolean;

  basefile: string;

  filepath: string;
  relpath: string;

begin
  {$ifdef windows}
  try
    addedfiles:=tstringlist.create;

    tiny:=cbTiny.Checked;

    CETRAINER:=ExtractFilePath(filename)+'CET_TRAINER.CETRAINER';

    if tiny then
    begin
      //temporarily insert this in front of the lua script
      MainForm.frmLuaTableScript.assemblescreen.BeginUpdate;
      MainForm.frmLuaTableScript.assemblescreen.Lines.Insert(0, 'RequiredCEVersion='+floattostr(ceversion));
      MainForm.frmLuaTableScript.assemblescreen.Lines.Insert(1, 'if (getCEVersion==nil) or (getCEVersion()<RequiredCEVersion) then');
      MainForm.frmLuaTableScript.assemblescreen.Lines.Insert(2, '  messageDialog(''Please install '+strCheatEngine+' ''..RequiredCEVersion, mtError, mbOK)');
      MainForm.frmLuaTableScript.assemblescreen.Lines.Insert(3, '  closeCE()');
      MainForm.frmLuaTableScript.assemblescreen.Lines.Insert(4, 'end');
    end;


    try
      SaveTable(CETRAINER, true);
    finally
      if tiny then
      begin
        //undo that addition
        for i:=0 to 4 do
          MainForm.frmLuaTableScript.assemblescreen.Lines.Delete(0);

        MainForm.frmLuaTableScript.assemblescreen.EndUpdate;
      end;
    end;



    btnGenerateTrainer.caption:=rsSaving+rot;
    btnGenerateTrainer.enabled:=false;
    saving:=true;

    application.ProcessMessages;
    try
      if tiny then basefile:='tiny' else basefile:='standalonephase1';

      if (fileexists(cheatenginedir+basefile+'.dat')=false) then
      begin
        if (fileexists(cheatenginedir+basefile+'.cepack')) then
          ceunpackfile(cheatenginedir+basefile+'.cepack', cheatenginedir+basefile+'.dat', true);
      end;

      if CopyFile(cheatenginedir+basefile+'.dat', filename) then
      begin
        updatehandle:=BeginUpdateResourceA(pchar(filename), false);
        if updatehandle<>0 then
        begin
          _archive:=TMemorystream.create; //create the archive

          if not tiny then
          begin
            //all files go into a compressed archive

            filecount:=0;
            _archive.WriteBuffer(filecount, sizeof(filecount)); //allocate space for the filecount  (omg trainers will be thirtytwo bits longer!)

            case comboCompression.itemindex of
              0: compression:=clnone;
              1: compression:=clfastest;
              2: compression:=cldefault;
              3: compression:=clmax;
            end;

            archive:=Tcompressionstream.create(compression, _archive, true);


            decompressor:=TMemorystream.create;

            if (fileexists(cheatenginedir+'standalonephase2.dat')=false) and
               (fileexists(cheatenginedir+'standalonephase2.cepack')) then
              ceunpackfile(cheatenginedir+'standalonephase2.cepack', cheatenginedir+'standalonephase2.dat', true);

            decompressor.LoadFromFile(cheatenginedir+'standalonephase2.dat');

            addfile(CETRAINER);
            deletefile(cetrainer);

            //first the custom files (this way you can override files with your own from other folders)
            for i:=0 to listview1.Items.Count-1 do
              addfile(TFileData(listview1.items[i].data).filepath, TFileData(listview1.items[i].data).folder);

            addfile(cheatenginedir+'defines.lua');

            if rb32.checked then
            begin
              addfile(cheatenginedir+'cheatengine-i386.exe');

              addfile(cheatenginedir+'lua53-32.dll');
              addfile(cheatenginedir+'win32\dbghelp.dll','win32');

              if cbSpeedhack.checked then
                addfile(cheatenginedir+'speedhack-i386.dll');

              if cbvehdebug.checked then
                addfile(cheatenginedir+'vehdebug-i386.dll');

              if cbKernelDebug.checked then
              begin
                addfile(cheatenginedir+'dbk32.sys');
                addfile(cheatenginedir+'dbk64.sys');
                addfile(cheatenginedir+'cheatengine-i386.exe.sig');
              end;

              if cbModPlayer.checked then
                addfile(cheatenginedir+'libmikmod32.dll');


              if cbCCode.checked then
                addfile(cheatenginedir+'tcc32-32.dll');
            end
            else
            begin
              addfile(cheatenginedir+'cheatengine-x86_64.exe');
              addfile(cheatenginedir+'lua53-64.dll');

              if cbSpeedhack.checked then
                addfile(cheatenginedir+'speedhack-x86_64.dll');

              if cbvehdebug.checked then
                addfile(cheatenginedir+'vehdebug-x86_64.dll');

              if cbKernelDebug.checked then
              begin
                addfile(cheatenginedir+'dbk64.sys');
                addfile(cheatenginedir+'cheatengine-x86_64.exe.sig');
              end;

              if cbModPlayer.checked then
                addfile(cheatenginedir+'libmikmod64.dll');

              if cbCCode.checked then
                addfile(cheatenginedir+'tcc64-64.dll');
            end;

            if cbIncludes.checked then
              addfolder(cheatenginedir+'include','include');


            if cbDotNet.checked then
            begin
              addfile(cheatenginedir+'DotNetDataCollector32.exe');
              addfile(cheatenginedir+'DotNetDataCollector64.exe');
            end;

            if cbD3DHook.checked then
            begin
              addfile(cheatenginedir+'overlay.fx');
              if rb32.checked then
              begin
                addfile(cheatenginedir+'d3dhook.dll');
                addfile(cheatenginedir+'ced3d9hook.dll');
                addfile(cheatenginedir+'ced3d10hook.dll');
                addfile(cheatenginedir+'ced3d11hook.dll');
              end
              else
              begin
                addfile(cheatenginedir+'d3dhook64.dll');
                addfile(cheatenginedir+'ced3d9hook64.dll');
                addfile(cheatenginedir+'ced3d10hook64.dll');
                addfile(cheatenginedir+'ced3d11hook64.dll');
              end;
            end;

            //do the exe trainer features
            for i:=0 to length(exeTrainerFeatures)-1 do
              if (exeTrainerFeatures[i].cb<>nil) and exeTrainerFeatures[i].cb.checked then
              begin
                try
                  ltop:=lua_gettop(luavm);
                  lua_rawgeti(luavm, LUA_REGISTRYINDEX, exeTrainerFeatures[i].functionid) ;
                  if lua_pcall(luavm, 0,1,0)=0 then
                  begin
                    if lua_istable(luavm,-1) then
                    begin
                      t:=lua_gettop(luavm);
                      for j:=1 to lua_objlen(luavm, t) do
                      begin
                        lua_pushinteger(luavm, j);
                        lua_gettable(luavm, t);
                        if lua_istable(luavm, -1) then
                        begin
                          t2:=lua_gettop(Luavm);
                          lua_pushstring(Luavm,'PathToFile');
                          lua_gettable(Luavm, t2);
                          if lua_isstring(Luavm, -1) then
                            filepath:=Lua_ToString(LuaVM,-1)
                          else
                            filepath:='';

                          lua_pop(luavm,1);

                          if filepath<>'' then
                          begin
                            lua_pushstring(Luavm,'RelativePath');
                            lua_gettable(Luavm, t2);
                            if lua_isstring(Luavm, -1) then
                              relpath:=Lua_ToString(LuaVM,-1)
                            else
                              relpath:='';

                            lua_pop(luavm,1);

                            addFile(filepath,relpath);
                          end;

                        end;
                        lua_pop(luavm,1);
                      end;
                    end;
                  end;

                finally
                  lua_settop(luavm,ltop);
                end;
              end;

            archive.free;

            pinteger(_archive.Memory)^:=filecount;  //fill in the count (uncompressed)


          end
          else
            _archive.LoadFromFile(CETRAINER); //tiny version has the .cetrainer only


          {_Archive.SaveToFile('c:\bla.dat');}

          try

            if not UpdateResourceA(updatehandle, RT_RCDATA, 'ARCHIVE', 0, _archive.memory, _archive.size) then
              raise exception.create(rsFailureOnWriting+rsARCHIVE+inttostr(
                getlasterror()));

            if not tiny then
            begin
              //tiny has no decompressor
              if not UpdateResourceA(updatehandle, RT_RCDATA, 'DECOMPRESSOR', 0, decompressor.memory, decompressor.size) then
                raise exception.create(rsFailureOnWriting+rsDECOMPRESSOR+inttostr(
                  getlasterror()));
            end;

            icon:=tmemorystream.create;
            try
              image1.picture.icon.SaveToStream(icon);
             // sizeof(TBitmapInfoHeader)

              //GetIconInfo();

              z:=TIcon.create;
             // z.LoadFromFile('F:\svn\favicon.ico');
              //z.SaveToStream(icon);

              ii:=icon.memory;

              if ii.idType=1 then
              begin
                if ii.idCount>0 then
                begin
                  //update the icon
                  if not updateResourceA(updatehandle,pchar(RT_ICON),MAKEINTRESOURCE(1),1033, pointer(ptruint(icon.Memory)+ii.icondirentry[0].dwImageOffset), ii.icondirentry[0].dwBytesInRes) then
                    raise exception.create(rsIconUpdateError+' 2');

                  //update the group
                  gii.idCount:=1;
                  gii.icondirentry[0].id:=1;
                  if not updateResourceA(updatehandle,pchar(RT_GROUP_ICON),MAKEINTRESOURCE(101),1033, gii, sizeof(TGRPICONDIR)+sizeof(TGRPICONDIRENTRY)) then
                    raise exception.create(rsIconUpdateError+' 3');


                end
                else
                  raise exception.create(rsIconUpdateError+' 4 '+rsInvalidIcon);
              end
              else
                raise exception.create(rsIconUpdateError+' 5 '+rsInvalidIconType);
            finally
              icon.free;

            end;

          finally
            if EndUpdateResource(updatehandle, false)=false then
              raise exception.create(format(rsUpdateFailed,[getLastError]));
          end;
        end else raise exception.create(
          rsFailureOpeningTheTrainerForResourceUpdates);

        showmessage(rsTheTrainerHasBeenSuccessfullyGenerated);
      end
      else
        showMessage(Format(rsTrainerFileMissing, [cheatenginedir+basefile, filename]));


    finally
      if _archive<>nil then
        freeandnil(_archive);

      saving:=false;
      btnGenerateTrainer.enabled:=true;


      if addedfiles<>nil then
        freeandnil(addedfiles);
    end;

  except
    on e: exception do
      MessageDlg(e.message, mtError,[mbok],0);
  end;
  {$else}
  raise exception.create('not implemented yet');
  {$endif}
end;

procedure TfrmExeTrainerGenerator.addDirToList(dir: string);
var dirinfo: TSearchRec;
  r: integer;
begin
  ZeroMemory(@DirInfo,sizeof(TSearchRec));

  while dir[length(dir)]=pathdelim do //cut of \
    dir:=copy(dir,1,length(dir)-1);

  {$warn 5044 off}

  r := FindFirst(dir + pathdelim+'*.*', FaAnyfile, DirInfo);
  while (r = 0) do
  begin
    if (DirInfo.Attr and FaVolumeId <> FaVolumeID) then
    begin
      if ((DirInfo.Attr and FaDirectory) <> FaDirectory) then
        addFiletoList(dir + pathdelim + DirInfo.Name)
      else
      begin
        if (DirInfo.Name[1]<>'.') then
          addDirToList(dir + pathdelim + DirInfo.Name);
      end;
    end;

    r := FindNext(DirInfo);
  end;

  {$warn 5044 on}
  FindClose(DirInfo);
end;


procedure TfrmExeTrainerGenerator.addFiletoList(fn: string);
var f: TFiledata;
  d: string;
  li: TListItem;
begin
  f:=tfiledata.create;
  f.filepath:=fn;
  f.filename:=extractfilename(fn);

  d:=ExtractFilePath(fn);
  d:=ExtractRelativepath(cheatenginedir, d);
  if (pos(':', d)>0) or (pos('..', d)>0) then
    d:='';

  f.folder:=d;

  li:=listview1.Items.Add;
  li.caption:=f.filename;
  li.SubItems.Add(d);
  li.Data:=f;
end;

procedure TfrmExeTrainerGenerator.Button3Click(Sender: TObject);
begin
  if SelectDirectoryDialog1.Execute then
    addDirToList(SelectDirectoryDialog1.FileName);
end;

procedure TfrmExeTrainerGenerator.cbCCodeChange(Sender: TObject);
begin
  cbIncludes.checked:=cbCCode.checked;
end;

procedure TfrmExeTrainerGenerator.cbTrainersizeChange(Sender: TObject);
begin
  groupbox1.enabled:=cbGigantic.checked;
  GroupBox2.enabled:=cbGigantic.checked;
  rb32.enabled:=cbGigantic.Checked;
  rb64.enabled:=cbGigantic.checked;
  cbSpeedhack.enabled:=cbGigantic.Checked;
  cbVEHDebug.enabled:=cbGigantic.checked;
  cbModPlayer.Enabled:=cbGigantic.checked;
  cbKernelDebug.enabled:=cbGigantic.Checked;

  label1.enabled:=cbGigantic.checked;
  comboCompression.enabled:=cbGigantic.checked;

  GroupBox3.enabled:=cbGigantic.checked;
  ListView1.enabled:=cbGigantic.checked;
  Button3.enabled:=cbGigantic.checked;

  btnAddFile.enabled:=cbGigantic.checked;
  btnRemoveFile.enabled:=listview1.Selected<>nil;

end;

procedure TfrmExeTrainerGenerator.Button1Click(Sender: TObject);
begin
  image1.picture.icon:=pickIcon;
end;

procedure TfrmExeTrainerGenerator.btnAddFileClick(Sender: TObject);
var i: integer;
begin
  if opendialog1.execute then
  begin
    for i:=0 to opendialog1.Files.count-1 do
      addFileToList(opendialog1.Files[i]);
  end;
end;

procedure TfrmExeTrainerGenerator.btnRemoveFileClick(Sender: TObject);
var i: integer;
begin
  i:=0;
  while i<listview1.items.count do
  begin
    if listview1.Items[i].Selected then
    begin
      TFileData(listview1.items[i].data).free;
      listview1.items.Delete(i);
    end
    else
      inc(i);
  end;

end;

procedure TfrmExeTrainerGenerator.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var i: integer;
begin
  closeaction:=cafree;
  frmExeTrainerGenerator:=nil;

  for i:=0 to ListView1.Items.Count-1 do
    TFiledata(listview1.items[i].Data).free;

  for i:=0 to length(exeTrainerFeatures)-1 do
    if exeTrainerFeatures[i].cb<>nil then
      freeandnil(exeTrainerFeatures[i].cb);
end;

procedure TfrmExeTrainerGenerator.FormCloseQuery(Sender: TObject;
  var CanClose: boolean);
begin
  canclose:=not saving;
end;

procedure TfrmExeTrainerGenerator.FormCreate(Sender: TObject);
var s,s2: string;
  i: integer;
begin
  comboCompression.Items.Clear;
  with comboCompression.Items do
  begin
    add(rsNone);
    add(rsFastest);
    add(rsDefault);
    add(rsMax);
  end;
  comboCompression.itemindex:=3;


  OpenDialog1.InitialDir:=CheatEngineDir;
  SelectDirectoryDialog1.InitialDir:=CheatEngineDir;

  //scan the current script for markers that might indicate a used feature
  s:=lowercase(mainform.frmLuaTableScript.assemblescreen.Text);

  cbSpeedhack.checked:=pos('speedhack_',s)>0;
  cbModPlayer.checked:=(pos('xmplayer_',s)>0) or (pos('xmplayer.',s)>0);
  cbKernelDebug.checked:=pos('dbk_',s)>0;
  cbD3DHook.checked:=pos('created3dhook',s)>0;
  cbDotNet.checked:=symhandler.hasDotNetAccess or (pos('dotnet',s)>0);

  for i:=0 to mainform.addresslist.Count-1 do
  begin

    if mainform.addresslist[i].VarType=vtAutoAssembler then
    begin
      if mainform.addresslist[i].AutoAssemblerData.script<>nil then
      begin
        s:=mainform.addresslist[i].AutoAssemblerData.script.text;
        s2:=uppercase(s);

        if (cbCCode.Checked=false) then
        begin
          if (pos('{$C}', s2)>0) or (pos('{$CCODE',s2)>0) then
            cbCCode.Checked:=true;
        end;

        if (cbCCode.checked) then
        begin
          if pos('#include', s)>0 then
          begin
            cbIncludes.checked:=true;
            break;
          end;
        end;
      end;
    end;
  end;

  if mainform.LuaForms.count=1 then  //if there is only one form use that icon as default
    image1.Picture.Icon:=TCEForm(mainform.LuaForms[0]).icon
  else   //else check if there is a TRAINERFORM
  for i:=0 to mainform.LuaForms.count-1 do
    if TCEForm(mainform.LuaForms[i]).Name='TRAINERFORM' then
    begin
      //use the icon from this form
      image1.Picture.Icon:=TCEForm(mainform.LuaForms[i]).icon;
      break;
    end;

  for i:=0 to length(exeTrainerFeatures)-1 do
    if exeTrainerFeatures[i].featurename<>'' then
    begin
      exeTrainerFeatures[i].cb:=TCheckBox.Create(self);
      exeTrainerFeatures[i].cb.Caption:=exeTrainerFeatures[i].featurename;
      exeTrainerFeatures[i].cb.Parent:=GroupBox2;
    end;
end;

procedure TfrmExeTrainerGenerator.FormShow(Sender: TObject);
var
  i,s:integer;
  {$ifdef windows}
  cbi: TComboboxInfo;
  {$endif}
  extrasize: integer;
begin
  i:=max(max(button3.Width, btnAddFile.Width), btnRemoveFile.Width);

  button3.width:=i;
  btnAddFile.Width:=i;
  btnRemoveFile.Width:=i;
  groupbox3.Constraints.MinHeight:=panel1.height;

  {$ifdef windows}
  cbi.cbSize:=sizeof(cbi);
  if GetComboBoxInfo(comboCompression.handle, @cbi) then
    extrasize:=cbi.rcButton.Right-cbi.rcButton.Left+cbi.rcItem.Left
  else
  {$endif}
    extrasize:=16;

  s:=0;
  for i:=0 to comboCompression.Items.Count-1 do
    s:=max(s, canvas.GetTextWidth(comboCompression.items[i]));

  comboCompression.Constraints.MinWidth:=s+extrasize;
end;

procedure TfrmExeTrainerGenerator.ListView1ContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
begin

end;

procedure TfrmExeTrainerGenerator.ListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
begin
  btnRemoveFile.enabled:=listview1.Selected<>nil;
end;

procedure TfrmExeTrainerGenerator.miEditFolderClick(Sender: TObject);
var z: TFiledata;
begin
  if listview1.Selected<>nil then
  begin
    z:=TFiledata(listview1.Selected.data);
    InputQuery(rsNewFoldername, rsCETrainerMaker, z.folder);
    listview1.Selected.SubItems[0]:=z.folder;
  end;
end;

procedure TfrmExeTrainerGenerator.pmFilesPopup(Sender: TObject);
begin
  miEditFolder.enabled:=ListView1.Selected<>nil;

end;

initialization
  {$I frmExeTrainerGeneratorUnit.lrs}

end.

